/*****************************************************
*                                                                          
*               COPYRIGHT (c) 2015-2017 Hargic Corporation                 
*                         All Rights Reserved                              
*                                                                          
* The source code contained or described herein and all documents          
* related to the source code ("Material") are owned by Hargic            
* Corporation or its licensors.  Title to the Material remains             
* with Hargic Corporation or its suppliers and licensors.                  
*                                                                          
* The Material is protected by worldwide copyright and trade secret        
* laws and treaty provisions. No part of the Material may be used,         
* copied, reproduced, modified, published, uploaded, posted, transmitted,  
* distributed, or disclosed in any way except in accordance with the       
* applicable license agreement.                                            
*                                                                          
* No license under any patent, copyright, trade secret or other            
* intellectual property right is granted to or conferred upon you by       
* disclosure or delivery of the Materials, either expressly, by            
* implication, inducement, estoppel, except in accordance with the         
* applicable license agreement.                                            
*                                                                          
* Unless otherwise agreed by Hargic in writing, you may not remove or      
* alter this notice or any other notice embedded in Materials by Hargic    
* or Hargic's suppliers or licensors in any way.                           
*                                                                          
** Author: shengda.huang
** Date: 2018-11-24
*
*****************************************************/

/***** Include files ********************************/
#include "sys_shell.h"
#include <stdio.h>
#include <string.h>
/***** Defines **************************************/
#define sysshell_log(_fmt_, ...)   printf("[SYSSHELL][%s:%d][%s] "_fmt_"\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)

#define SYS_SHELL_CMD_MAX           16

#define SYS_SHELL_CMD_ARGS_MAX      8

/***** Define structure *****************************/
typedef struct 
{
    unsigned char   used;
    char            *name;
    char            *desc;
    int             (*callback)(int argc, char** argv);
} sys_shell_cmd_t;

/***** Define constant ******************************/

/***** Define global ********************************/
const char sys_shell_showcmd[] = "CMD\t\tDESCRIPTION";
const char sys_shell_prefix[] = "shell>>";
const char sys_shell_help1[] = "?";
const char sys_shell_help2[] = "help";
const char sys_shell_quit[]  = "quit";

const char sys_shell_enter[] = "\r\n";
const char sys_shell_CR = 0x0d;
const char sys_shell_LF = 0x0a;

static sys_shell_cmd_t shell_cmd[SYS_SHELL_CMD_MAX];

/***** Define Prototype of functions ****************/

/**
 * @brief
 * @param  None
 * @retval None
 */
int sys_shell_init(void)
{
    printf("%s", sys_shell_prefix);
    return 0;
}

int sys_shell_register(char *cmd, char *desc, int (*func)(int, char**))
{
    int i;
    sys_shell_cmd_t *cmd_desc;

    for (i=0; i<SYS_SHELL_CMD_MAX; i++)
    {
        cmd_desc = &shell_cmd[i];
        if (cmd_desc->used == 0)
        {
            cmd_desc->name = cmd;
            cmd_desc->desc = desc;
            cmd_desc->callback = func;
            cmd_desc->used = !0;
            return 0;
        }
    }
    if (i >= SYS_SHELL_CMD_MAX)
    {
        sysshell_log("add '%s' failed cmd list if full", cmd);
        return -1;
    }

    // !!!make compiler happy, should not access here
    return -2;
}

static void sys_shell_dump(char *desc, unsigned char *data, int len)
{
    unsigned int i;

    printf("=========================================\n");
    printf("This is %s size %d dump data:", desc, len);
    for(i=0; i<len; i++)
    {
        if (i % 32 == 0)
            printf("\n");
        printf(" %02x", data[i]);
    }
    printf("\n");
    printf("=========================================\n");
}

static void sys_shell_show_help(void)
{
    sys_shell_cmd_t *cmd;
    int i;

    printf("%s\r\n%s\r\n%s\r\n%s\r\n", sys_shell_showcmd, sys_shell_help1, sys_shell_help2, sys_shell_quit);
    for (i=0; i<SYS_SHELL_CMD_MAX; i++)
    {
        cmd = &shell_cmd[i];
        if (cmd->used != 0)
            printf("%s\t\t%s\r\n", cmd->name, cmd->desc);
    }
}

int sys_shell_handler(char *input, int inlen)
{
    // sys_shell_dump("shell recv:", (unsigned char *)input, inlen);

    // only enter
    if (inlen == 0)
        goto final;

    if (   (strncmp((const char *)input, sys_shell_help1, strlen(sys_shell_help1)) == 0) \
        || (strncmp((const char *)input, sys_shell_help2, strlen(sys_shell_help2)) == 0) )
    {
        // sysshell_log("get help opertation");
        sys_shell_show_help();
        goto final;
    }

    if (strncmp((const char *)input, sys_shell_quit, strlen(sys_shell_quit)) == 0)
    {
        // sysshell_log("get quit opertation");
        return SYS_SHELL_EXIT;
    }

    char *sep = " \t\n\r";
    char *lasts;
    int argc, i;
    char *argv[SYS_SHELL_CMD_ARGS_MAX];
    sys_shell_cmd_t *cmd;

    argc = 0;
    memset(argv, 0x0, SYS_SHELL_CMD_ARGS_MAX);

    argv[argc] = strtok_r((char *)input, sep, &lasts);
    while (argv[argc])
    {
        if (argc < (SYS_SHELL_CMD_ARGS_MAX-1))
        {
            argv[++argc] = strtok_r((char *)0, sep, &lasts);
        }
        else
        {
            sysshell_log("too many arguments given for a command: max = %d", SYS_SHELL_CMD_ARGS_MAX - 1);
            break;
        }
    }
    argv[argc] = 0;

    // sysshell_log("get %d args:", argc);
    // for (i=0; i<argc; i++)
    //     sysshell_log("%s", argv[i]);

    for (i=0; i<SYS_SHELL_CMD_MAX; i++)
    {
        cmd = &shell_cmd[i];
        if (cmd->used != 0 && strncmp(argv[0], cmd->name, strlen((const char *)argv[0])) == 0)
            break;
    }
    if (i >= SYS_SHELL_CMD_MAX)
    {
        sysshell_log("there is not cmd '%s'", argv[0]);
        goto final;
    }

    if (cmd->callback != (void *)0)
        (*cmd->callback)(argc, &argv[0]);

final:
    printf("%s", sys_shell_prefix);
    return SYS_SHELL_SUCCESS;
}

/* End of file */



